package com.example.common.rc.aop.curl_aop;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.SneakyThrows;
import org.aspectj.lang.JoinPoint;
import org.springframework.http.HttpMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zjarlin
 * @since 2023/8/2 15:51
 */
public class CurlUtil {

    static String formatCurlCommand(String curlCommand) {
        // Ensure each '-H', '-d', or '-' followed by a letter is in a new line
        curlCommand = curlCommand.replaceAll("(?<=(-[Hd]|- )[^\\s])", "\\\n$1");
        return curlCommand;
    }

    @SneakyThrows
    static String generateCurlCommand(HttpServletRequest request, JoinPoint joinPoint) {
        StringBuilder curlCommand = new StringBuilder();

        // Append curl command with HTTP method and URL
        String method = request.getMethod();
        String requestURL = request.getRequestURL().toString();
        curlCommand.append("curl -X ").append(" ").append(method).append(" ")
        ;

        // Append request headers
        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String, String> headers = Collections.list(headerNames)
                .stream()
                .filter(CurlUtil::needHeader)
                .collect(Collectors.toMap(headerName -> headerName, request::getHeader));

        headers.forEach((headerName, headerValue) -> curlCommand.append("-H \"").append(escapeQuotes(headerName)).append(": ").append(escapeQuotes(headerValue)).append("\" "));

        // Append request body or query parameters
        if (HttpMethod.GET.matches(method)||HttpMethod.DELETE.matches(method)) {
            Map<String, String> queryParams = getQueryParams(request);
            String queryString = queryParams.entrySet()
                    .stream()
                    .map(entry -> entry.getKey() + "=" + entry.getValue())
                    .collect(Collectors.joining("&"));
            curlCommand
                    .append(" \"").append(requestURL)
//                    .append("\" ")

                    .append("?").append(queryString).append("\" ");

        } else {
            Object[] args = joinPoint.getArgs();
            for (Object arg : args) {
                if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                    continue;
                }
                if (arg instanceof Map) {
                    Map<String, String> queryParams = getQueryParamsFromMap((Map<?, ?>) arg);
                    String queryString = queryParams.entrySet()
                            .stream()
                            .map(entry -> entry.getKey() + "=" + entry.getValue())
                            .collect(Collectors.joining("&"));
                    curlCommand.append("\"?").append(queryString).append("\" ");
                } else {
//                    String requestBody = JSON.toJSONString(arg);

                    ObjectMapper objectMapper = new ObjectMapper() {{
                        enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
                        enable(SerializationFeature.WRITE_NULL_MAP_VALUES);
                    }};
                    String requestBody = objectMapper.writeValueAsString(arg);

//                    String requestBody = getRequestBody(arg);
                    if (requestBody != null && !requestBody.isEmpty()) {
                        String str = escapeQuotes(requestBody);
//                        String str = escapeQuotes(requestBody);
                        curlCommand.append("-d \"").append(str).append("\" ")
                                .append(" \"").append(requestURL).append("\" ")
                        ;
                    }
                }
            }
        }

        String s = curlCommand.toString() .replaceAll("\\s+", " ");
        final String fix = System.lineSeparator();
        String s11 = StrUtil.addPrefixIfNot(s, fix);
        String s2 = StrUtil.addSuffixIfNot(s11, fix);
        return s2; // Remove extra whitespaces and make it single-line


    }

    private static String escapeQuotes(String input) {
        return input.replace("\"", "\\\"");
    }

    private static boolean needHeader(String headerName) {
        List<String> list = Arrays.asList("X-Access-Token", "Content-Type");
        // Add common header names here
        boolean b = list.stream().anyMatch(e -> StrUtil.containsIgnoreCase(e, headerName));
        return b;
    }

    private static Map<String, String> getQueryParams(HttpServletRequest request) {
        Map<String, String> queryParams = new HashMap<>();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            String paramValue = request.getParameter(paramName);
            queryParams.put(paramName, paramValue);
        }
        return queryParams;
    }

    private static Map<String, String> getQueryParamsFromMap(Map<?, ?> paramMap) {
        Map<String, String> queryParams = new HashMap<>();
        for (Map.Entry<?, ?> entry : paramMap.entrySet()) {
            String key = String.valueOf(entry.getKey());
            String value = String.valueOf(entry.getValue());
            queryParams.put(key, value);
        }
        return queryParams;
    }
}
